/**
 * 是否是函数
 * @param {*} val
 * @returns
 */
export function isFunction(val) {
  return typeof val === "function";
}

/**
 * 是否是对象
 * @param {*} val
 */
export function isObject(val) {
  return typeof val === "object" && val != null;
}

const callbacks = [];
let waiting = false;
function flushCallbacks() {
  callbacks.forEach((cb) => cb());
  waiting = false;
}
function timers(flushCallbacks) {
  let timerFn = () => {};
  if (Promise) {
    timerFn = () => {
      Promise.resolve().then(flushCallbacks);
    };
  } else if (MutationObserver) {
    let textNode = document.createTextNode(1);
    let observe = new MutationObserver(flushCallbacks);
    observe.observe(textNode, {
      characterData: true,
    });

    timerFn = () => {
      textNode.textContent = 3;
    };
  } else if (setImmediate) {
    timerFn = () => {
      setImmediate(flushCallbacks);
    };
  } else {
    timerFn = () => {
      setTimeout(flushCallbacks, 0);
    };
  }
  timerFn();
}

export function nextTick(cb) {
  callbacks.push(cb);
  if (!waiting) {
    timers(flushCallbacks); // vue2中考虑了兼容性问题， vue3里面不再考虑
    waiting = true;
  }
}

let lifecycleHooks = [
  "beforeCreate",
  "created",
  "beforeMount",
  "mounted",
  "beforeUpdate",
  "updated",
  "beforeDestroy",
  "destroyed",
  "activated",
  "deactivated",
  "errorCaptured",
];

function mergeHook(parentVal, childVal) {
  // {}  => {x: []}
  if (childVal) {
    if (parentVal) {
      return parentVal.concat(childVal);
    } else {
      return [childVal];
    }
  } else {
    return parentVal;
  }
}

let strats = {};
lifecycleHooks.forEach((hook) => {
  strats[hook] = mergeHook;
});

strats.components = function (parentVal, childVal) {
  // childVal.prototype =  Object.create(parentVal);
  let options = {};
  // 根据父对象构造一个新对象， options.__proto__

  options = Object.create(parentVal);

  if (childVal) {
    for (let key in childVal) {
      options[key] = childVal[key];
    }
  }
  return options;
};

/**
 * 合并options
 * @param {*} parent
 * @param {*} child
 */
export function mergeOptions(parent, child) {
  const options = {};
  for (let key in parent) {
    mergeField(key);
  }
  for (let key in child) {
    if (parent.hasOwnProperty(key)) {
      continue; // 导致parent无值报错
    }
    mergeField(key);
  }

  function mergeField(key) {
    let parentVal = parent[key];
    let childVal = child[key];
    // 策略模式
    if (strats[key]) {
      // 如果有对应的策略就调用对应的策略即可
      options[key] = strats[key](parentVal, childVal);
    } else {
      if (isObject(parentVal) && isObject(childVal)) {
        options[key] = { ...parentVal, ...childVal };
      } else {
        options[key] = childVal || parentVal;
      }
    }
  }

  return options;
}

export function isReservedTag(str) {
  return (function () {
    let reservedTag = "a,div,span,p,img,button,ul,li";
    // 源码根据 “,” 生成映射表  {a: true, div: true, p: true}
    return reservedTag.includes(str);
  })();
}
